package com.iscreen.dbupgrade.queries.mysql;

import java.util.Iterator;
import java.util.List;

import com.iscreen.dbupgrade.DBUpgrade;
import com.iscreen.dbupgrade.objects.CreateTable;
import com.iscreen.dbupgrade.objects.HashPartitions;
import com.iscreen.dbupgrade.objects.NewField;
import com.iscreen.dbupgrade.objects.Partitions;
import com.iscreen.dbupgrade.objects.RangePartition;
import com.iscreen.dbupgrade.objects.RangePartitions;
import com.iscreen.dbupgrade.queries.CreateTableQuery;
import com.iscreen.dbupgrade.queries.QueryUtils;
import com.iscreen.dbupgrade.queries.constants.DBConstants;
import com.iscreen.dbupgrade.queries.objects.PartitionType;
import com.iscreen.dbupgrade.queries.objects.PrimaryKey;
import com.iscreen.utils.constants.Constants;
import com.iscreen.utils.db.DBUtils;
import com.iscreen.utils.strings.StringUtils;

public class MySqlCreateTable extends CreateTableQuery
{

	protected MySqlCreateTable(CreateTable query)
	{
		super(query);
	}
	
	public String getSql()
	{
		StringBuilder sqlBuilder = new StringBuilder();
		addCreateTableClause(sqlBuilder);
		sqlBuilder.append(Constants.STR_NEW_LINE);
		addCreateDefinitions(sqlBuilder);
		sqlBuilder.append(Constants.STR_NEW_LINE);
		addTableOptions(sqlBuilder);
		sqlBuilder.append(Constants.STR_NEW_LINE);
		addPartitionsClause(sqlBuilder);
		return sqlBuilder.toString();
	}

	private void addCreateDefinitions(StringBuilder sqlBuilder)
	{
		sqlBuilder.append("(");
		addFieldsClause(sqlBuilder);
		addPrimaryKeyClause(sqlBuilder);
		sqlBuilder.append(Constants.STR_NEW_LINE);
		sqlBuilder.append(")");
	}

	private void addTableOptions(StringBuilder sqlBuilder)
	{
		addCommentClause(sqlBuilder);
	}

	private void addCreateTableClause(StringBuilder sqlBuilder)
	{
		sqlBuilder.append(DBConstants.CREATE_TABLE + " " + getTableName() + " ");
	}

	private void addFieldsClause(StringBuilder sqlBuilder)
	{
		QueryUtils utils = DBUpgrade.getInstance().getFactory().getQueryUtils();
		List<NewField> fields = getFields();
		for (Iterator<NewField> itField = fields.iterator(); itField.hasNext();)
		{
			NewField field = itField.next();
			sqlBuilder.append(field.getName() + " "
					+ utils.getFieldTypeSql(field) + " ");
			if (field.isMandatory() != null && field.isMandatory())
			{
				sqlBuilder.append(DBConstants.NOT_NULL + " ");
			}
			if (field.getDefault() != null)
			{
				sqlBuilder.append(DBConstants.DEFAULT + " "
						+ field.getDefault());
			}
			sqlBuilder.append(DBConstants.COMMENT + " '"
					+ DBUtils.getQuotedString(field.getDescription()) + "' ");

			if (itField.hasNext())
			{
				sqlBuilder.append(",");
				sqlBuilder.append(Constants.STR_NEW_LINE);
			}
		}
	}

	private void addPrimaryKeyClause(StringBuilder sqlBuilder)
	{
		PrimaryKey primaryKey = getPrimaryKey();
		if (primaryKey != null)
		{
			sqlBuilder.append(",");
			sqlBuilder.append(Constants.STR_NEW_LINE);
			sqlBuilder.append(DBConstants.CONSTRAINT + " "
					+ primaryKey.getName() + " ");
			sqlBuilder.append(DBConstants.PRIMARY_KEY + " ("
					+ StringUtils.listToString(primaryKey.getPkFields(), ",")
					+ ")");
		}
	}

	private void addCommentClause(StringBuilder sqlBuilder)
	{
		sqlBuilder.append(DBConstants.COMMENT + " '"
				+ DBUtils.getQuotedString(getDescription()) + "' ");
	}

	private void addPartitionsClause(StringBuilder sqlBuilder)
	{
		Partitions partitions = getPartitions();
		if (partitions != null)
		{
			PartitionType partitionType = getPartitionType();
			sqlBuilder.append(DBConstants.PARTITION_BY + " "
					+ partitionType + " ");

			switch (partitionType)
			{
				case RANGE:
					addRangePartitionsClause(sqlBuilder);
					;
					break;
				case HASH:
					addHashPartitionsClause(sqlBuilder);
					break;
				}
		}
	}

	private void addRangePartitionsClause(StringBuilder sqlBuilder)
	{
		RangePartitions rangePartitions = getPartitions().getRangePartitions();
		sqlBuilder.append("(" + rangePartitions.getPartitionBy() + ") ");
		sqlBuilder.append(Constants.STR_NEW_LINE);
		sqlBuilder.append("(");
		for (Iterator<RangePartition> itPartition = rangePartitions.getRangePartition().iterator(); itPartition.hasNext();)
		{
			RangePartition partition = itPartition.next();
		
			sqlBuilder.append(DBConstants.PARTITION + " " + partition.getName()
					+ " ");
			sqlBuilder.append(DBConstants.VALUES + " " + DBConstants.LESS_THAN
					+ " (" + partition.getMaxValue() + ")");
			if (itPartition.hasNext())
			{
				sqlBuilder.append(",");
				sqlBuilder.append(Constants.STR_NEW_LINE);
			}
		}
		sqlBuilder.append(")");

	}

	private void addHashPartitionsClause(StringBuilder sqlBuilder)
	{
		HashPartitions hashPartitions = getPartitions().getHashPartitions();
		sqlBuilder.append("(" + hashPartitions.getPartitionBy() + ") ");
		sqlBuilder.append(DBConstants.PARTITIONS + " "
				+ hashPartitions.getNumPartitions() + " ");
	}

}
